package org.watchrecords.dbo;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang.StringUtils;
import org.watchrecords.annotations.Email;
import org.watchrecords.annotations.UniqueNamed;
import org.watchrecords.constants.Role;

import com.agimatec.validation.constraints.NotEmpty;
import com.mallardsoft.tuple.Pair;
import com.mallardsoft.tuple.Tuple;

@Entity
@NamedQueries({
@NamedQuery(name = "checkUniqueName", query = "SELECT COUNT(u) FROM User u WHERE u.id <> :id AND u.name = :name"),
@NamedQuery(name = "getUserByName", query = "SELECT u FROM User u WHERE u.name = :username"),
@NamedQuery(name = "authenticateUser", query = "SELECT u FROM User u WHERE u.name = :username AND u.password = :password"),
@NamedQuery(name = "getUsersByRole", query = "SELECT u FROM User u WHERE u.role = :role"),
@NamedQuery(name = "getUsers", query = "SELECT u FROM User u ORDER BY u.name"),
})
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "name"))
public class User implements Identifiable {
    /**
     * 
     */
    private static final long serialVersionUID = 1453549461887965046L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Column(nullable = false)
    @NotEmpty(message = "User name cannot be empty")
    private String name;
    
    @Column(nullable = false)
    @NotEmpty(message = "Password cannot be empty")
    private String password;
    
    @Email
    private String email;
    private Date registrationDate;
    
    @Column(nullable = false)
    @NotNull(message = "You must select a role")
    private Role role;
    
    private String characterName;
    private Integer argentNode;
    
    @Transient
    private String originalPassword;
    @Transient
    private String confirmPassword;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getRegistrationDate() {
        return registrationDate;
    }

    public void setRegistrationDate(Date registrationDate) {
        this.registrationDate = registrationDate;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCharacterName() {
        return characterName;
    }

    public void setCharacterName(String characterName) {
        this.characterName = characterName;
    }

    public Integer getArgentNode() {
        return argentNode;
    }

    public void setArgentNode(Integer argentNode) {
        this.argentNode = argentNode;
    }

    public String getOriginalPassword() {
        return originalPassword;
    }

    public void setOriginalPassword(String originalPassword) {
        this.originalPassword = originalPassword;
    }

    public String getConfirmPassword() {
        return confirmPassword;
    }

    public void setConfirmPassword(String confirmPassword) {
        this.confirmPassword = confirmPassword;
    }
    
    @AssertTrue(message = "Passwords do not match")
    public boolean isPasswordsMatch() {
        return originalPassword == null || (originalPassword.equals(password) && StringUtils.isEmpty(confirmPassword)) || StringUtils.equals(password, confirmPassword);
    }
    
    @UniqueNamed(message = "A user with this name already exists")
    public Pair<Integer, String> getIdAndName() {
        return Tuple.from(id, name);
    }
}
